import MBase from "../utils/m-base";
import MFile from "../utils/m-file";
import MWriter from "../services/m-writer";
import { IParsedModel, IReqMethod } from "../m-types";
import { IProp, IType, IParm } from "../m-types";

/**js+axios文件书写器 */
export default class WriterJsAxios extends MWriter {
  /**书写枚举 */
  protected async writeEnums() {}

  /**书写模型 */
  protected async writeModels() {
    const { data, dir } = this;
    for (const m of data.models) {
      const { name, description, uses, props } = m;
      const path = `${dir}/models/${name}.js`;
      //定义文件框架
      const lines: Array<string> = [];

      //添加文件提示
      lines.push(...this.getFileTips());

      //添加一个空行
      lines.push("\t");

      //添加模型备注
      lines.push(...MBase.toCNote(description));

      //添加模型定义开头
      lines.push(`export default class ${name} {`);

      //添加模型属性
      const body: Array<string> = [];
      for (const p of props) body.push(...this.getModelProp(p));
      lines.push(...MBase.ident(body, 2));

      //添加一个空行
      lines.push("\t");

      //添加模型构造器
      lines.push(...this.getModelConstructor(m));

      //添加模型结尾
      lines.push("}");

      //添加一个空行
      lines.push("\t");

      //写入文件
      await MFile.writeFile(path, MBase.toRows(lines));
    }
  }

  /**书写请求函数 */
  protected async writeMethods() {
    const { data, dir } = this;
    for (const m of data.methods) {
      const group = m.group || "";
      const base = m.base || "";
      const urls = m.urls || [];
      const funcs = m.funcs || [];
      const path = `${dir}/${group}.js`;
      //定义文件框架
      const lines: Array<string> = [];

      //添加文件提示
      lines.push(...this.getFileTips());

      //添加模型引用
      const imports: Array<string> = [];
      imports.push(`import axios from "axios";`);
      lines.push(...imports);

      //添加两个空行
      lines.push("\t\t");

      //添加请求项目名称
      const baseName = `const baseName = "${base}";`;
      lines.push(...[...MBase.toCNote("定义请求项目名称"), baseName]);

      //添加两个空行
      lines.push("\t\t");

      //添加请求地址
      const paths: Array<string> = [];
      for (const u of urls) {
        const { name, description, value } = u;
        const desc = MBase.toCNote(description);
        const dim = `export const ${name} = "${value}";`;
        paths.push(...[...desc, dim]);
      }
      lines.push(...paths);

      //添加两个空行
      lines.push("\t\t");

      //添加请求函数
      const apis: Array<string> = [];
      for (const f of funcs) {
        apis.push(...this.getMethodFunc(f));
      }
      lines.push(...apis);

      //添加一个空行
      lines.push("\t");

      //写入文件
      await MFile.writeFile(path, MBase.toRows(lines));
    }
  }

  /**获取请求函数定义 */
  private getMethodFunc(func: IReqMethod) {
    const { name, method, urlName, description } = func || {};
    const { inputParms, inputModel } = func || {};
    const hasModel = inputModel.length > 0;
    const parm = this.getMethodParm(inputParms);
    const parms = parm.filter((x) => !x.inPath).map((x) => x.name);
    const paths = parm.filter((x) => x.inPath).map((x) => x.name);
    //定义函数框架
    const lines: Array<string> = [];
    //添加函数注释
    lines.push(...MBase.toCNote(description));

    //添加函数定义
    let mParm = hasModel ? `reqBody, ` : "";
    if (parm.length > 0) {
      mParm = `${mParm}reqParm: { `;
      parm.forEach((x) => (mParm = `${mParm}${x.name}, `));
      mParm = `${MBase.trimStr(mParm, ",")} }, `;
    }
    mParm = `${mParm}reqConfig`;
    lines.push(`export function ${name}(${mParm}) {`);

    //添加函数任务
    let mConf = "";
    const task: Array<string> = [];
    task.push(`let reqUrl = ${urlName};`);
    task.push(`const reqConf = { ...reqConfig };`);
    task.push(`const reqHeaders = { baseName, ...reqConf.headers };`);
    if (parm.length > 0) {
      task.push(`const { ${parm.map((x) => x.name).join(", ")} } = reqParm;`);
    }
    if (paths.length > 0) {
      task.push(`const reqPaths = { ${paths.join(", ")} };`);
      task.push(
        "reqUrl = reqUrl.replace(/\\{([^\\}]+)\\}/g, (m, p) => reqPaths[p]);"
      );
    }
    if (parms.length > 0) {
      task.push(`const reqParams = { ...reqConf.params };`);
      task.push(`Object.assign(reqParams, { ${parms.join(", ")} });`);
      mConf = `{ ...reqConfig, ...{ headers: reqHeaders, params: reqParams } }`;
    } else {
      mConf = `{ ...reqConfig, ...{ headers: reqHeaders } }`;
    }
    task.push("return new Promise((resolve, reject) => {");

    //添加axios定义
    const axios: Array<string> = [];
    //请求实例处理
    let dim = "";
    if (method == "put" || method == "post") {
      const mData = hasModel ? "reqBody" : "null";
      dim = `const resTask = axios.${method}(reqUrl, ${mData}, ${mConf});`;
    } else {
      dim = `const resTask = axios.${method}(reqUrl, ${mConf});`;
    }
    axios.push(dim);

    //添加任务回调
    axios.push(`resTask.then(x => resolve(x.data));`);
    axios.push(`resTask.catch(x => reject(x));`);

    //把axios定义添加到任务定义中
    task.push(...MBase.ident(axios, 2));

    //任务结尾
    task.push("});");

    //把任务定义添加到文件框架中
    lines.push(...MBase.ident(task, 2));

    //添加函数结尾
    lines.push("}");

    return lines;
  }

  /**获取模型属性定义字符串 */
  private getModelProp(prop: IProp) {
    const { name, description } = prop || {};
    const note = MBase.toCNote(description);
    const valueStr = this.getModelValueStr(prop);
    const dim = `${name} = ${valueStr};`;
    return [...note, dim];
  }

  /**获取模型构造函数定义字符串 */
  private getModelConstructor(model: IParsedModel) {
    const m = model || {};
    const props = m.props || [];
    const name = m.name || "";
    const desc = m.description || "";
    const lines: Array<string> = [];
    lines.push(...MBase.toCNote(desc || `实例化${name}`));
    lines.push(`constructor(data) {`);
    const body: Array<string> = [];
    body.push(`if (!data) return;`);
    for (const p of props) {
      const name = p.name || "";
      const value = this.getModelValueStr(p);
      body.push(`this.${name} = data.${name} || ${value};`);
    }
    lines.push(...MBase.ident(body, 2));
    lines.push(`}`);
    return MBase.ident(lines, 2);
  }

  /**获取请求函数参数 */
  private getMethodParm(parm: Array<IParm>) {
    const dims = parm.map((x) => {
      const name = x.name || "";
      if (!name) return { name: "", inPath: false };
      return { name, inPath: x.inPath };
    });
    return dims.filter((x) => !!x.name);
  }

  /**获取默认值字符串 */
  private getModelValueStr(prop: IProp) {
    const { type, required, nullable } = prop || {};
    const must = required || !nullable;
    const first = (type || [])[0] || {};
    const fType = first.type;
    const format = first.format || "";
    const num1 = "number,long,short,int,integer,int32,int64";
    const num2 = "double,float,decimal";
    const obj = "object,file,blob";
    const isDate = format.includes("date");
    if (fType == "array") return "[]";
    if (!must || isDate || obj.includes(fType)) return "null";
    if (num1.includes(fType)) return "0";
    if (num2.includes(fType)) return "0.0";
    if (fType === "string") return `""`;
    if (fType === "boolean") return "false";
    return `new ${fType}()`;
  }
}
/**注册js+axios书写器 */
MWriter.register("js+axios", WriterJsAxios);
